package pl.matt.media.extractor;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;

import pl.matt.media.manager.MediaManagersFactory;
import pl.matt.media.model.ImageType;
import pl.matt.media.utils.RectangleUtils;
import pl.matt.model.Rectangle;

/**
 * @deprecated
 * @author mateusz
 * 
 */
public abstract class AbstractExtractor implements Extractor {

	private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AbstractExtractor.class);
	
	private ImageType imageType = ImageType.JPEG;
	
	public AbstractExtractor() {
		
	}
	
	/**
	 * znalezione twarze
	 */
	private List<Collection<Rectangle>> detectionResults = new ArrayList<Collection<Rectangle>>();
	
	private Rectangle countFromNeighbours(int index) {
		Rectangle result = null;
		// wektor 2 klatek z tyłu
		Rectangle before = null;
		if (index > 1) {
			Rectangle r1 = detectionResults.get(index-2).iterator().next();
			Rectangle r2 = detectionResults.get(index-1).iterator().next();
			before = r1.getNext(r2);
		} 
		if (index == 1) {
			before = detectionResults.get(index-1).iterator().next();
		}
		
		
		// wektor 2 klatek z przodu
		Rectangle after = null;
		if (index + 2 < detectionResults.size()) {
			Collection<Rectangle> c1 = detectionResults.get(index+2);
			Collection<Rectangle> c2 = detectionResults.get(index+1);
			if (c1 != null && c1.size() == 1 && c2 != null && c2.size() == 1) {
				Rectangle r1 = c1.iterator().next();
				Rectangle r2 = c2.iterator().next();
				after = r1.getNext(r2);
			}
		}
		if (after != null && index + 2 == detectionResults.size()) {
			Collection<Rectangle> c = detectionResults.get(index+1);
			if (c != null && c.size() == 1) {
				after = detectionResults.get(index+1).iterator().next();
			}					
		}
		// średnia z tych wektorów
		if (after != null && before != null) {
			result = RectangleUtils.getAverageRectangle(before, after);
		} else if (after != null) {
			result = after;
		} else if (before != null) {
			result = before;
		} else {
			LOG.warn("Trudności w znalezieniu obrazu. Szukam pierwszego następnej dla klatki: " + index);
			Collection<Rectangle> lastChanceRectangles = null;
			for (int i = index; i < detectionResults.size(); i++) {
				Collection<Rectangle> nextRectangles = detectionResults.get(i);
				if (nextRectangles != null && nextRectangles.size() == 1) {
					result = nextRectangles.iterator().next();
					break;
				}
				if (CollectionUtils.isNotEmpty(nextRectangles) && lastChanceRectangles == null) {
					lastChanceRectangles = nextRectangles;
				}
			}
			if (result == null && lastChanceRectangles != null) {
				result = lastChanceRectangles.iterator().next();
			}					
		}
		return result;
	}
	
	/**
	 * @return lista plików
	 */
	protected abstract List<File> getFiles();
	
	protected abstract Collection<Rectangle> extract(File file);
	
	public List<Rectangle> extract() throws IOException {

		List<File> files = getFiles();
		for (File file : files) {
			Collection<Rectangle> faces = extract(file);
			detectionResults.add(faces);
			LOG.debug(file.getAbsolutePath() + " <-- file detected objects count: " + (faces == null ? 0 : faces.size()));
		}

		int index = 0;
		for (Collection<Rectangle> rectangles : detectionResults) {
			if (CollectionUtils.isEmpty(rectangles)) {
				Rectangle result = countFromNeighbours(index);				
				if (result == null) {
					LOG.error("Nie znaleziono szukanego obrazu dla klatki: " + index);					
				} else {
					// sprawdzam czy obraz się mieści
					Rectangle imageRectangle = MediaManagersFactory.getImageManager().getImageRectangle(files.get(index));
					if (result.getWidth() > imageRectangle.getWidth()) {
						result.setX(0);
						result.setWidth(imageRectangle.getWidth());
					}
					if (result.getHeight() > imageRectangle.getHeight()) {
						result.setY(0);
						result.setHeight(imageRectangle.getHeight());
					}
					if (result.getX() + result.getWidth() >  imageRectangle.getWidth()) {
						result.setX(imageRectangle.getWidth() - result.getWidth());
					}
					if (result.getY() + result.getHeight() >  imageRectangle.getHeight()) {
						result.setY(imageRectangle.getHeight() - result.getHeight());
					}
					detectionResults.set(index, Arrays.asList(result));
				}
			} else if (rectangles.size() > 1) {
				// wylicz prawidłowy obraz na podstawie bliskości z sąsiednimi klatkami
				Rectangle result = null;
				Rectangle countedResult = countFromNeighbours(index);
				if (countedResult == null) {
					LOG.error("Nie znaleziono szukanego obrazu dla klatki: " + index);
					detectionResults.set(index, Arrays.asList(rectangles.iterator().next()));
				} else {
					int minDistance = Integer.MAX_VALUE;
					for (Rectangle rectangle : rectangles) {
						int distance = countedResult.getDistance(rectangle);
						if (distance < minDistance) {
							minDistance = distance;
							result = rectangle;
						}
					}
				}
				detectionResults.set(index, Arrays.asList(result));			
			}			
			index++;
		}

		// zapis obrazków
		List<Rectangle> out = new ArrayList<Rectangle>(detectionResults.size());
		index = 0;
		for (Collection<Rectangle> rectangles : detectionResults) {
			File source = files.get(index);
			File result = getResultFile(source, index);
			Rectangle rectangle = rectangles.iterator().next();
			LOG.debug(rectangle + " <-- rectangle + index: " + index);
			MediaManagersFactory.getImageManager().cropImage(source.getAbsolutePath(), result.getAbsolutePath(), rectangle, imageType);	
			index++;
			out.add(rectangle);
		}
		return out;
	}
	
	protected abstract File getResultFile(File inputFile, int imageIndex);

}
